#include "BayesianFilterSerializer.h"
#include "Test_BayesianFilter.h"

#include "stdio.h"
#include "stdlib.h"
#include <iostream>
#include <fstream>
#include <time.h>
#include "Log.h"


#define MAX_TAGS 32
#define TRIES 10


using namespace std;

set<string> Test_BayesianFilter::ReadDiccionary ()
{
	ifstream f;
	f.open("words");

	if ( !f.is_open () )
	{
		cout << "UNABLE TO OPEN words FILE!!!" << endl;
		cout.flush ();
	}

	cout << "  Reading dictionary file... ";

	string str;
	set<string> words;
	int count = 0;
	while ( !f.eof () )
	{
		f >> str;
		words.insert(str);
		count++;
	}

	f.close ();
	cout << count << " words read." << endl;

	return words;
}

void Test_BayesianFilter::TestSerialization(BayesianFilter& bf)
{
	bf.AddTag ( "Pingocho" );
	bf.AddTag ( "Sopifofo" );
	bf.AddTag ( "Endomorfico" );

	set<string> tags;
	tags.insert("Pingocho");

	set<string> words = ReadDiccionary();
	bf.Train(words,tags);

	cout << endl << "Now serializing...";
	cout.flush();

	BayesianFilterSerializer ser(bf);
	ser.Serialize("Bayes.data","Bayes.matrix");

	cout << "Ready." << endl << "Now deserializing...";

	try
	{
		ser.Deserialize("Bayes.data","Bayes.matrix");
	}
	catch ( char* ex )
	{
		cout << "Exception thrown!!!" << endl << ex << endl;
	}

	cout << "Ready." << endl << endl;
	Dump(bf);
}

void Test_BayesianFilter::StartTest (BayesianFilter& bf)
{
	bf.AddTag ( "Pingocho" );
	bf.AddTag ( "Sopifofo" );
	bf.AddTag ( "Endomorfico" );

	set<string> words;
	set<string> tags;
	tags.insert("Pingocho");
	tags.insert("Sopifofo");
	words.insert("Pirulo");
	words.insert("demoniaco");

	bf.Train (words,tags);
	bf.Train (words,tags);

	set<BayesianFilterResult*> chk = bf.Classify(words);
	Dump(bf);

	cout << endl << "Now serializing...";
	cout.flush();

	BayesianFilterSerializer ser(bf);
	ser.Serialize("Bayes.data","Bayes.matrix");

	cout << "Ready." << endl << "Now deserializing...";

	try
	{
		ser.Deserialize("Bayes.data","Bayes.matrix");
	}
	catch ( char* ex )
	{
		cout << "Exception thrown!!!" << endl << ex << endl;
	}

	cout << "Ready." << endl << endl;
	Dump(bf);
}

string ToString ( int n )
{
	char buffer [ 10 ];
	sprintf(buffer,"%d",n);

	string retval = buffer;
	return retval;
}

void Test_BayesianFilter::MeasureEfficiency()
{
	BayesianFilter* bf;
	cout << "Starting BayesianFilter efficiency measurement..." << endl;

	ifstream f;
	f.open("words");

	if ( !f.is_open () )
	{
		cout << "UNABLE TO OPEN words FILE!!!" << endl;
		cout.flush ();
		return;
	}

	cout << "  Reading dictionary file... ";

	string str;
	set<string> words;
	int count = 0;
	while ( !f.eof () )
	{
		f >> str;
		words.insert(str);
		count++;
	}

	f.close ();
	cout << count << " words read." << endl;

	cout << "  Measuring tag addition... " << endl;
    cout << "    Training first tag..." << endl;



	bf = new BayesianFilter ();
	bf->AddTag("Tag0");
	set<string> setTags;
	setTags.insert("Tag0");
	bf->Train(words,setTags);

	for ( int y = 2 ; y <= MAX_TAGS ; y++ )
	{
		string str = "Tag";
		str += ToString(y);

		cout << "    Adding tag number " << y << "... ";
		clock_t start = clock ();
		bf->AddTag ( str );
		clock_t end = clock();
		cout << (double) (end - start) / (double) CLOCKS_PER_SEC << " seconds " << endl;
	}

	cout << "  Measuring tag deletion..." << endl;

	for ( int y = 2 ; y <= MAX_TAGS ; y++ )
	{
		string str = "Tag";
		str += ToString(y);

		cout << "    Deleting tag number " << y << "... ";
		clock_t start = clock ();
		bf->RemoveTag ( str );
		clock_t end = clock();
		cout << (double) (end - start) / (double) CLOCKS_PER_SEC << " seconds " << endl;
	}

	cout << "  Measuring massive word insertion... " << endl;

	for ( int i = 1 ; i <= MAX_TAGS ; i++ )
	{
		delete bf;
		bf = new BayesianFilter ();
		cout << "    Measuring " << i << " categories... " << endl;

		for ( int j = 0 ; j < i ; j++ )
		{
			string str = "Tag";
			str += ToString(j);
			bf->AddTag ( str );
		}

		set<string> tags;
		tags.insert("Tag0");

		clock_t start = clock ();
		bf->Train(words,tags);
		clock_t end = clock();
		
		cout << "      First try: " << (double) (end - start) / (double) CLOCKS_PER_SEC << " seconds " << endl;

		start = clock();
		for ( int z = 0 ; z < TRIES ; z++ )
			bf->Train(words,tags);
		end = clock();

		cout << "      Successive tries: " << (double) (end - start) / (double) (CLOCKS_PER_SEC * TRIES) << " seconds " << endl;
	}

	cout << "Measuring serialization...\n";

	clock_t start = clock ();
	BayesianFilterSerializer ser(*bf);
	ser.Serialize("ser.txt","matrix.txt");
	clock_t end = clock();
	cout << (double) (end - start) / (double) CLOCKS_PER_SEC << " seconds " << endl;

	return;

	cout << "Ready." << endl;
	cout.flush ();
}

void Test_BayesianFilter::Dump ( BayesianFilter& bf )
{
	LOG1("Test_BayesianFilter::Dump");
	LOG1("  Dumping tags...");
	
	map<string,__BayesianTag*>::iterator iter;
	for ( iter = bf.tags.begin() ; iter != bf.tags.end() ; iter++ )
	{
		string tagName = iter->first;
		__BayesianTag* tag = iter->second;

		cout << "    " << tagName << "\t\t  " << tag->pos << "\t  " << " " << tag->wordCount << " " << tag->trueCount << "/" << tag->falseCount << endl;
	}

	cout << endl;
	int size = (int) bf.tags.size();

	map<string,__BayesianProbability*>::iterator iterWord;
	for ( iterWord = bf.words.begin() ; iterWord != bf.words.end() ; iterWord++ )
	{
		cout << iterWord->first << "\t";

		__BayesianProbability* p = iterWord->second;
		for ( int j = 0 ; j < size ; j++ )
			cout << p[j].trueCount << "/" << p[j].falseCount << "\t";

		cout << endl;
	}

	cout.flush ();
}
